
lualsp = {};

s = [[
rect = cast('Rect',rect);
rect.pp = cast('Rect.Point',rect);
rect.
]]
--
local function GetValues(s)
    local pos;
    local valTable = {};
    while(true)do
        local ps,pe,val,typ,val2 = string.find(s,'([%w_.]*)%s*=?%s*cast%(%"?%\'?([%w_.]+)%"?%\'?,?([^)]*)',pos);
        if(ps==nil)then
            break;
        end
        if(val~="")then
            valTable[val] = typ;
        else
            valTable[val2] = typ;
        end
        pos = pe;
    end
    return valTable;
end

local function GetWord(code)
    local ps,pe,str = code:find('%s*([%w_.:]+)%s*$');
    if(str==nil)then return str; end;
    local c = str:sub(#str);
    if(c==nil)then c = ""; end;
    if(c=='.' or c==':')then
        str = str:sub(1,#str-1);
    end
    return str,c;
end

local codeUpdate = false;
local pathsCode = {
['path'] = {
    code = [[
function Rect:GetX()
end
Rect:GetY()

]],    --源码
    initd = nil,
    typeinfo = {
        {name='Type',field='field'},
        }
    }
}

--符号类型
local Types = {
['name'] = {
        ['field'] = {type = 'Type',path='path',line=line,col=col,complItem={}},
    }
}

local function updateTypeInfo(code,path)
    local pos;
    local typeinfo = {};
    if(path)then
        --清楚所有有关该path的code类型信息
        if(pathsCode[path] and pathsCode[path].typeinfo)then
            for k,v in ipairs(pathsCode[path].typeinfo)do
                if(v.clear)then
                    v.clear();
                end
            end
        end
    end

    while(true)do
        local ps,pe,typ,field = code:find('([%w_]+)%s*:([%w_]+)',pos);
        if(ps==nil)then break; end;
        local f = {};
        f.path = path;
        f.pos = ps;
        f.complItem = {};
        f.complItem.label = field;
        if(Types[typ]==nil)then Types[typ] = {}; end;
        Types[typ][field] = f;

        pos = pe;

        --生成pathCode
        local info = {};
        info.type = typ;
        info.field = field;
        info.pos = ps;

        info.clear = function()
            Types[typ][field] = nil;
        end

        table.insert(typeinfo,info);
    end
    return typeinfo;
end

--如果代码已经改变则,字段信息,并更新Types
local function updateCode()
    for path,v in pairs(pathsCode)do
        local code = v.code;
        if(code and v.initd~=true)then
            local infos = updateTypeInfo(code,path);
            v.typeinfo = infos;
            v.initd = true;
        end
    end
end

--查找所有类型,字段信息,并更新Types
local function updateAllCode()
    for path,v in pairs(pathsCode)do
        local code = v.code;
        if(code)then
            local infos = updateTypeInfo(code,path);
            v.typeinfo = infos;
            v.initd = true;
        end
    end
end

local function GetComplTypeList(valName,code,c)
    local vals = GetValues(code);
    local list = {};
    updateCode();
    if(vals)then
        local typ = vals[valName];
        if(typ)then
            if(Types[typ])then
                for k,v in pairs(Types[typ])do
                    table.insert(list,v.complItem);
                end
            end
        else
            --假设没有类型信息,则可能是,var.filed.field ...
            local pos;
            valName = valName..c;
            local ps,pe,val = valName:find('([%w_]+)%.',pos);
            if(ps)then
                local typ;
                while(true)do
                    pos = pe;
                    local typName = vals[val];
                    typ = Types[typName];

                    ps,pe,field = valName:find('([%w_]+)%.',pos);
                    if(ps==nil or typ==nil)then
                        break;
                    end;
                    --暂时先这么实现
                    local fieldName = typName .. '.' .. field;
                    val = fieldName;
                end
                if(typ)then
                    for k,v in pairs(typ)do
                        table.insert(list,v.complItem);
                    end
                end
            end
        end
    end
    return list;
end

--同步文档信息
function lualsp:didChange(json,path,code)
    if(pathsCode[path]==nil)then pathsCode[path]={}; end;
    pathsCode[path].code = code;
    pathsCode[path].initd = nil;
end

--
function lualsp:codeCompleteAt(json,path,line,col)
    local code = self:GetCode(json);
    io.stderr:write('<<',path,':',line,':',col,'>>\n');
    io.stderr:flush();
    local comp = Compl.init(json.id);
    if(code)then
        local pos = 0;
        local l = line;
        while(true)do
            l = l - 1;
            if(pos==nil or l<1)then
                break;
            end
            pos = pos + 1;
            pos = code:find('\n',pos);
        end
        pos = pos + col;
        local cur_code = code:sub(1,pos);
        local word,c = GetWord(cur_code);
        if(word)then
            local list = GetComplTypeList(word,cur_code,c);
            for k,v in ipairs(list)do
                comp:AddItem(v);
            end
        end
    end
    --补全
    -- local comp = Compl.init(json.id);
    -- comp:AddItem({
    --     label = 'word01',
    -- });
    -- comp:AddItem({
    --     label = 'word02',
    -- });
    comp:End();
end

function lualsp:init(json)
    --遍历工作目录
    local path = json.params.rootPath;
    if(path)then
        local files = FindFiles(path..'\\*.lua');
        for k,path in ipairs(files)do
            path = path:gsub('\\','/');
            if(path:sub(2,2)==':')then
                path = path:sub(1,1)..path:sub(2);
            end
            local file = io.open(path,"rb");
            io.stderr:write(path,"\n");
            if(file)then
                if(pathsCode[path]==nil)then pathsCode[path]={}; end;
                pathsCode[path].code = file:read('*a');
                pathsCode[path].initd = nil;
            end
        end
        io.stderr:flush();
    end

    return {
        capabilities = {
            completionProvider = {   --补全
                resolveProvider = false,
                triggerCharacters = {
                    ".",":"
                    }
            },
        textDocumentSync = 1,  --同步
    }};
end



RPC_Loop(function(json)
    -- body
    Message_proc(json,lualsp);
end)
